﻿using System;
using Mnk.Merger.Code.Common;
using Mnk.Merger.Code.Repository;
using Mnk.Merger.Code.Settings;

namespace Mnk.Merger.Code.Commands
{
    class Merger : IMerger
    {
        private readonly IRepositoryFacade facade;
        private readonly IProcessExecutor executor;
        private readonly MergeConfig mergeConfig;

        public Merger(IRepositoryFacade facade, IProcessExecutor executor, MergeConfig mergeConfig)
        {
            this.facade = facade;
            this.executor = executor;
            this.mergeConfig = mergeConfig;
        }

        public bool DoValidation(string workingDirectory)
        {
            foreach (var command in mergeConfig.Validation)
            {
                Console.WriteLine("Validate: " + command);
                executor.Execute(command, workingDirectory);
            }
            return true;
        }

        public bool DoCommit(string workingDirectory, string mergeUrl, string revisions)
        {
            if (string.IsNullOrEmpty(revisions))
            {
                Console.WriteLine("Nothing to commit");
                return false;
            }
            Console.WriteLine("Commit to: {0}, revisions: {1}", workingDirectory, revisions);
            facade.Commit(workingDirectory, mergeUrl, revisions);
            return true;
        }

        public bool DoMerge(string workingDirectory, string mergeUrl, string revisions)
        {
            if (!string.IsNullOrEmpty(revisions))
            {
                Console.WriteLine("Please commit all the changes before merge");
                return false;
            }

            var toMerge = facade.GetRevisionToMerge(workingDirectory, mergeUrl);
            if (string.IsNullOrEmpty(toMerge.RevisionsToMerge))
            {
                Console.WriteLine("Nothing to merge");
                return false;
            }
            foreach (var op in mergeConfig.OperationsBeforeMerge)
            {
                switch (char.ToUpper(op))
                {
                    case 'C':
                        Console.WriteLine("Cleanup folder: {0}", workingDirectory);
                        facade.CleanUp(workingDirectory);
                        break;
                    case 'R':
                        Console.WriteLine("Revert folder: {0}", workingDirectory);
                        facade.Revert(workingDirectory);
                        break;
                    case 'U':
                        Console.WriteLine("Update folder: {0}", workingDirectory);
                        facade.Update(workingDirectory);
                        break;
                    default:
                        throw new ArgumentException("Unknown command: " + op);
                }
            }
            Console.WriteLine("Merge to: {0}, revision: {1}, from: {2}", workingDirectory, toMerge.RevisionsToMerge, mergeUrl);
            return facade.Merge(workingDirectory, mergeUrl, toMerge.RevisionsToMerge);
        }

        public void DoAutoMerge(string workingDirectory, string mergeUrl, string revisions, bool validate)
        {
            while (DoMerge(workingDirectory, mergeUrl, revisions))
            {
                if (validate && !DoValidation(workingDirectory)) break;
                revisions = facade.GetLatestMergedRevisions(workingDirectory, mergeUrl);
                if (!DoCommit(workingDirectory, mergeUrl, revisions)) break;
                revisions = facade.GetLatestMergedRevisions(workingDirectory, mergeUrl);
                Console.WriteLine();
            }
        }
    }
}